<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
WebAnt
</title>
</head>
<body onload="init();">
<script type="text/javascript" language="javascript" src="map.js" ></script>
<script type="text/javascript" language="javascript" src="neural.js" ></script>
<script type="text/javascript" language="javascript" src="critter.js" ></script>
<script type="text/javascript">

 var ctx;

 var lastSave = 0;
 var maxX = 5000; 
 var maxY = 3000; 
 var maxCrop;
 var maxFoodValue;
 var foodGrowthRate;
 var maxEnergyValue;
 var maxCritter;
 var ups;      //update speed
 var dist;
 var metabolism;
 var fitMode;
 
 var iterations = 0;
 
 var crop = new CropField(maxCrop);
 var critters = new Array();
 
 var viewport = {left: 0, right: 1000, top: 0, bottom: 600};
 var dragging = false;
 var drag = {x: 0, y: 0};
 
 var someCode = [
//[],
];
  
 function init()
 {
    apply();
    document.getElementsByTagName('canvas')[0].width = viewport.right - viewport.left;
    document.getElementsByTagName('canvas')[0].height = viewport.bottom - viewport.top;
    
    ctx = document.getElementsByTagName('canvas')[0].getContext('2d');
    for (var i = 0; i < maxCritter / 2; i++)
    {
        if (someCode.length > 0)
        {
            var mom = Math.min(Math.round(Math.random()*someCode.length), someCode.length - 1);
            var dad = Math.min(Math.round(Math.random()*someCode.length), someCode.length - 1);
            critters.push(new critter(Math.random()*maxX, Math.random()*maxY, crossover(mutate(someCode[mom]),mutate(someCode[dad]))));
        }
        else
            critters.push(new critter(Math.random()*maxX, Math.random()*maxY));
    }
    
    for (i = 0; i < maxCrop; i++)
    {
        crop.push(new food(Math.random()*maxX, Math.random()*maxY, crop));
    }
    setTimeout(runCritters, ups);
 }
 
 function newCritter()
 {
    critters.push(new critter(Math.random()*maxX, Math.random()*maxY));
 }
 
 function mutate(code)
 {
    var retCode = code.slice();
    var i = parseInt(Math.random()*retCode.length);
    if (i >= retCode.length)
        i = retCode.length - 1;
    retCode[i] += 0.5*(1-2*Math.random());
    return retCode;
 }
 
 function crossover(code1, code2)
 {
    var len = Math.min(code1.length, code2.length);
    var retCode = new Array(len);
    for (var i = 0; i < len; i++)
    {
        retCode[i] = (Math.random() > 0.5) ? code1[i] : code2[i];
    }
    return retCode;
 }
  
 function runCritters()
 {
    if (iterations % 10 == 0)
        blank();
    var i;
    var best = 0;
    var bestval = [];
    for (i = 0; i < crop.length; i++)
    {
        fit(crop[i],fitMode);
        if (iterations % 10 == 0)
            crop[i].draw(ctx, viewport);
        crop[i].life++;
        if (crop[i].life > 5000)
            crop.splice(i,1);
    }
    for (i = 0; i < critters.length; i++)
    {
        with(critters[i])
        {
            update();
            move();
            interact(crop, critters);
            if (iterations % 10 == 0)
                draw(ctx, viewport);
            if (energy < 1)
            {
                if (crop.length < maxCrop)
                    crop.push(new food(x,y, crop));
                critters.splice(i,1);
            }
            else if (bestval < fitness)
            {
                best = i;
            }
        }
    }
    document.getElementById("status").value = '' + critters.length + ' vs ' + crop.length;
    
    if (critters[best])
    {
        if (critters[best].brain.toCode() != document.getElementById("bestcode").value)
            document.getElementById("bestcode").value = critters[best].brain.toCode();
        if (lastSave > 100 && critters[best].fitness > 100)
        {
            document.getElementById('bestcodes').innerHTML += '<br/>[' + critters[best].brain.toCode() + '],';
            lastSave = 0;
        }
    }    
    if (critters.length < maxCritter / 5)
    {
        newCritter();
    }
    
    lastSave++;
    setTimeout(runCritters, ups);
    
 }
 
 function blank() {
    ctx.fillStyle = 'rgba(0,0,0,0.9)';
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.save();
        ctx.translate(- viewport.left, - viewport.top);
        ctx.beginPath();
            ctx.moveTo(0,0);
            ctx.lineTo(maxX,0);
            ctx.lineTo(maxX,maxY);
            ctx.lineTo(0,maxY);
        ctx.closePath();
        ctx.strokeStyle = 'hsl(0,100%,50%)';
        ctx.stroke();
    ctx.restore();
 }
 
 function apply()
 {
    ups = parseInt(document.getElementById("ups_value").value);
    maxCrop = parseInt(document.getElementById("maxcrop_value").value);
    while (crop.length > maxCrop)
    {
     crop.remove(crop.length - 1);
    }
    crop.maxFood = maxCrop;
    maxFoodValue = parseInt(document.getElementById("maxfood_value").value);
    maxEnergyValue = parseInt(document.getElementById("maxenergy_value").value);
    metabolism = parseFloat(document.getElementById("metabolism_value").value);
    dist = parseFloat(document.getElementById("dist_value").value);
    maxCritter = parseFloat(document.getElementById("maxCritter_value").value);
     critters.length = (critters.length > maxCritter)?maxCritter:critters.length;
    foodGrowthRate = parseFloat(document.getElementById("foodGrowthRate_value").value);
    fitMode = document.getElementById("fitMode_value").value;
 }
 
 function onmouseMove(e) {
    if (dragging)
    {
	    var position = getRelativePosition(e);
	    viewport.left = drag.x - position.x;
	    viewport.right = viewport.left + ctx.canvas.width;
	    viewport.top = drag.y - position.y;
	    viewport.bottom = viewport.top + ctx.canvas.width;
	}
}

function onmouseDown(e)
{
    var pos = getRelativePosition(e);
    dragging = true;
    drag.x = pos.x + viewport.left;
    drag.y = pos.y + viewport.top;
}
function onmouseUp()
{
    dragging = false;
}

function getRelativePosition(e) {
	var t = ctx.canvas;
	var x = e.clientX+(window.pageXOffset||0);
	var y = e.clientY+(window.pageYOffset||0);
	do
		x-=t.offsetLeft+parseInt(t.style.borderLeftWidth||0),
		y-=t.offsetTop+parseInt(t.style.borderTopWidth||0);
	while (t=t.offsetParent);
	return {x:x,y:y};
}

</script>
<table>
    <tr>
        <td>
            <canvas width="1100" height="650" onmousemove="onmouseMove(event);" onmousedown="onmouseDown(event);" onmouseup="onmouseUp();"></canvas>
        </td>
        <td>
            <table style="height:80%;" border="1">
                <tr>
                    <td>update interval</td>
                    <td>
                        <input type="text" id="ups_value" value="1"/>
                    </td>
                </tr>
                <tr>
                    <td>maxCrop</td>
                    <td>
                        <input type="text" id="maxcrop_value" value="300"/>
                    </td>
                </tr>
                <tr>
                    <td>maxFoodValue</td>
                    <td>
                        <input type="text" id="maxfood_value" value="256"/>
                    </td>
                </tr>
                <tr>
                    <td>distance</td>
                    <td>
                        <input type="text" id="dist_value" value="400"/>
                    </td>
                </tr>
                <tr>
                    <td>foodGrowthRate</td>
                    <td>
                        <input type="text" id="foodGrowthRate_value" value="400"/>
                    </td>
                </tr>
                <tr>
                    <td>maxEnergyValue</td>
                    <td>
                        <input type="text" id="maxenergy_value" value="256"/>
                    </td>
                </tr>
                <tr>
                    <td>metabolism</td>
                    <td>
                        <input type="text" id="metabolism_value" value="0.997"/>
                    </td>
                </tr>
                
                <tr>
                    <td>maxCritter</td>
                    <td>
                        <input type="text" id="maxCritter_value" value="200"/>
                    </td>
                </tr>
                <tr>
                    <td>fitMode</td>
                    <td>
                        <select id="fitMode_value" >
                            <option value="torus">torus</option>
                            <option value="bounce">bounce</option>
                            <option value="kill">kill</option>
                            <option value="clip" selected="selected">clip</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>status</td>
                    <td>
                        <input type="text" id="status"/>
                    </td>
                </tr>
                <tr>
                    <td>bestcode</td>
                    <td>
                        <input type="text" id="bestcode"/>
                    </td>
                </tr>
                <tr>
                    <td>
                        <button onclick="apply();">Apply</button>
                    </td>
                    <td>
                        <button onclick="newCritter();">newCritter</button>
                    </td>
                </tr>
                
            </table>
        </td>
    </tr>
</table>
<div id="bestcodes"></div>
</body>
</html>